When we write components in Vue2, we define variables in options like props, data, methods, computed, and so on. During the component initialization phase, these options are handled internally by Vue by adding defined variables to the component instance. When the template is compiled into the render function, internal with(this){} syntax is used to access variables in the component instance.

So Vue3, the new setup startup function, is the entry point to the logical organization of the entire component. We can write the composition-API inside it to declare variables in a more intuitive form, which is good for the logical organization and reuse of the code, but let’s be clear. Composition-api is an ENHANCEMENT of API, it is not the paradigm of Vue3 component development. If the component is simple enough, options-API can be used. After understanding the application scenarios and usage of composition-API, we need to think further. How does the setup launcher function perform and how does the data it returns relate to the template?

Create and set up the component instance

First, let’s review the component rendering flow:Create a vnodeRendering vnodeCreate DOM.



Among themRendering vnodeThe process of mounting the component is basically:

const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) = > {
  // Create a component instance
  const instance = (initialVNode.component = createComponentInstance(initialVNode, parentComponent, parentSuspense))
  // Set the component instance
  setupComponent(instance)
  // Set up and run the render function with side effects
  setupRenderEffect(instance, initialVNode, container, anchor, parentSuspense, isSVG, optimized)
}
Copy the code

As you can see, the code that mounts the component does three main things: create the component instance, set up the component instance, and set up and run the render function with side effects. The first two processes are closely related to the problem we are exploring, starting with the process of creating a component instance and focusing on the implementation of the createComponentInstance method:

function createComponentInstance (vnode, parent, suspense) {
  // Inherits the appContext from the parent component instance, or directly from the root vNode if it is the root component.
  const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;
  const instance = {
    // Unique id of the component
    uid: uid++,
    / / component vnode
    vnode,
    // Parent component instance
    parent,
    // App context
    appContext,
    // VNode node type
    type: vnode.type,
    // Root component instance
    root: null.// New component vNode
    next: null.// Child node vnode
    subTree: null.// Update function with side effects
    update: null.// Render function
    render: null.// Render context proxy
    proxy: null.// Render context proxy with with block
    withProxy: null.// Responsive related objects
    effects: null.Dependency injection
    provides: parent ? parent.provides : Object.create(appContext.provides),
    // Render proxy's property access cache
    accessCache: null.// Render cache
    renderCache: [].// Render context
    ctx: EMPTY_OBJ,
    / / data data
    data: EMPTY_OBJ,
    / / props data
    props: EMPTY_OBJ,
    // Common attributes
    attrs: EMPTY_OBJ,
    // Slot related
    slots: EMPTY_OBJ,
    // A component or DOM ref reference
    refs: EMPTY_OBJ,
    // The reactive result returned by the setup function
    setupState: EMPTY_OBJ,
    // Setup function context data
    setupContext: null.// The registered component
    components: Object.create(appContext.components),
    // Register the directive
    directives: Object.create(appContext.directives),
    / / suspense
    suspense,
    // Suspense for asynchronous dependencies
    asyncDep: null.Suspense // Whether asynchronous dependencies are all handled
    asyncResolved: false.// Whether to mount
    isMounted: false.// Whether to uninstall
    isUnmounted: false.// Whether to activate
    isDeactivated: false.// Life cycle, before create
    bc: null.// Lifecycle, created
    c: null.// Lifecycle, before mount
    bm: null.// Mounted
    m: null.// Life cycle, before update
    bu: null.// Lifecycle, updated
    u: null.// Life cycle, unmounted
    um: null.// Lifecycle, before unmount
    bum: null.// Lifecycle deactivated
    da: null.// Lifecycle activated
    a: null.// Animate animate
    rtg: null.// Lifecycle render tracked
    rtc: null.// Lifecycle error captured
    ec: null.// Issue event methods
    emit: null
  }
  // Initialize the render context
  instance.ctx = { _: instance }
  // Initialize the root component pointer
  instance.root = parent ? parent.root : instance
  // Initializes the dispatch event method
  instance.emit = emit.bind(null, instance)
  return instance
}
Copy the code

As you can see from the code above, there are a number of properties defined on the component instance, many of which are defined to implement a scenario or function, with a general idea of what they do through the comments in the code.

Vue2 uses new Vue() to initialize a component instance, while Vue3 removes the Vue constructor and creates component instances directly by creating object literals. There is no essential difference between the two approaches, which refer to an object and then maintain the state data and context of the component throughout its life cycle

Once the instance instance is created, the next step is to set some of its properties. Now that the context of the component, the root component pointer, and the dispatch event method are set, there will be more logic to set instance properties.

This is where the setup function is handled. Let’s look at the implementation of the setupComponent method:

function setupComponent (instance, isSSR = false) {
  const { props, children, shapeFlag } = instance.vnode
  // Check if it is a stateful component
  const isStateful = shapeFlag & 4
  // Initialize props
  initProps(instance, props, isStateful, isSSR)
  // Initialize the slot
  initSlots(instance, children)
  // Set stateful component instances
  const setupResult = isStateful
    ? setupStatefulComponent(instance, isSSR)
    : undefined
  return setupResult
}
Copy the code
const shapeFlag = isString(type)
  ? 1 /* ELEMENT */
  : isSuspense(type)
    ? 128 /* SUSPENSE */
    : isTeleport(type)
      ? 64 /* TELEPORT */
      : isObject(type)
        ? 4 /* STATEFUL_COMPONENT */
        : isFunction(type)
          ? 2 /* FUNCTIONAL_COMPONENT */
          : 0
Copy the code

As you can see, we get props, children, shapeFlag, and other properties from the component vNode and initialize the props and slot, respectively. ShapeFlag encodes the type information of vNode, so that corresponding processing logic can be executed according to different types in the later patch stage. Here, according to the value of shapeFlag, we can determine whether this is a stateful component. If so, go a step further and set up instances of stateful components.

Next we’ll look at the setupStatefulComponent function, which does three things: create a render context proxy, judge the handling setup function, and complete component instance setup. It looks like this:

function setupStatefulComponent (instance, isSSR) {
  const Component = instance.type
  // Create a property access cache for the rendering proxy
  instance.accessCache = {}
  // Create the render context proxy
  instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)
  // Decide to handle the setup function
  const { setup } = Component
  if (setup) {
    If the setup function takes parameters, a setupContext is created
    const setupContext = (instance.setupContext =
      setup.length > 1 ? createSetupContext(instance) : null)
    // Execute the setup function to get the result
    const setupResult = callWithErrorHandling(setup, instance, 0 /* SETUP_FUNCTION */, [instance.props, setupContext])
    // Process the setup execution result
    handleSetupResult(instance, setupResult)
  }
  else {
    // Complete the component instance setup
    finishComponentSetup(instance)
  }
}
Copy the code

The first is the process of creating a render context proxy, which primarily proxies instance.ctx. Before analyzing the implementation, we need to consider the question, why do we need proxies here?

Create the render context proxy

Vue2 has similar data proxy logic, such as the data evaluated in props is stored on this._props, and the data defined in data is stored on this._data. Here’s an example:

<template>
  <p>{{ zz }}</p>
</template>
<script>
export default {
  data() {
    inZZ: true
  }
}
</script>
Copy the code

InZZ defined in data is stored on this._data inside the component when it initializes the component, whereas template rendering calls this.inZZ and actually calls this._data.inZZ because Vue2 initializes data, Make a layer of proxy proxy.

In Vue3, for easy maintenance, we store data in different states of components in different properties, such as setupState, CTX, data, props. When we execute the component rendering function, for the convenience of users, we will directly access the attributes in the rendering context instance. CTX, so we also need to make a layer of proxy to access and modify the attributes of the rendering context instance. CTX. Agent to access and modify data in setupState, CTX, data, props.

Now that we know what the proxy requirements are, we’ll examine the proxy methods: get, set, and HAS. When we access properties in the instance. CTX rendering context, we’ll enter the get function. Let’s look at its implementation:

const PublicInstanceProxyHandlers = {
  get ({ _: instance }, key) {
    const { ctx, setupState, data, props, accessCache, type, appContext } = instance
    if (key[0]! = ='$') {
      // setupState / data / props / ctx
      // The render agent's properties are accessed in the cache
      const n = accessCache[key]
      if(n ! = =undefined) {
        // fetch from the cache
        switch (n) {
          case 0: /* SETUP */
            return setupState[key]
          case 1 :/* DATA */
            return data[key]
          case 3 :/* CONTEXT */
            return ctx[key]
          case 2: /* PROPS */
            return props[key]
        }
      }
      else if(setupState ! == EMPTY_OBJ && hasOwn(setupState, key)) { accessCache[key] =0
        // Fetch data from setupState
        return setupState[key]
      }
      else if(data ! == EMPTY_OBJ && hasOwn(data, key)) { accessCache[key] =1
        // Fetch data from data
        return data[key]
      }
      else if (
        type.props &&
        hasOwn(normalizePropsOptions(type.props)[0], key)) {
        accessCache[key] = 2
        // Get data from props
        return props[key]
      }
      else if(ctx ! == EMPTY_OBJ && hasOwn(ctx, key)) { accessCache[key] =3
        // Fetch data from CTX
        return ctx[key]
      }
      else {
        // None
        accessCache[key] = 4}}const publicGetter = publicPropertiesMap[key]
    let cssModule, globalProperties
    // Public $XXX attribute or method
    if (publicGetter) {
      return publicGetter(instance)
    }
    else if (
      // The CSS module is injected when compiled by vue-loader
      (cssModule = type.__cssModules) &&
      (cssModule = cssModule[key])) {
      return cssModule
    }
    else if(ctx ! == EMPTY_OBJ && hasOwn(ctx, key)) {// User-defined attributes, also starting with '$'
      accessCache[key] = 3
      return ctx[key]
    }
    else if (
      // Globally defined attributes
      ((globalProperties = appContext.config.globalProperties),
        hasOwn(globalProperties, key))) {
      return globalProperties[key]
    }
    else if((process.env.NODE_ENV ! = ='production') &&
      currentRenderingInstance && key.indexOf('__v')! = =0) {
      if(data ! == EMPTY_OBJ && key[0= = ='$' && hasOwn(data, key)) {
        // If data defined in data starts with $, a warning is reported because $is a reserved character and does not act as a proxy
        warn(`Property The ${JSON.stringify(key)} must be accessed via $data because it starts with a reserved ` +
          `character and is not proxied on the render context.`)}else {
        // Warning if a variable used in a template is not defined
        warn(`Property The ${JSON.stringify(key)} was accessed during render ` +
          `but is not defined on instance.`)}}}}Copy the code

SetupState (); setupState (); setupState (); setupState (); setupState (); CTX includes computed properties, component methods, and some user-defined data.

If the key does not start with $, check whether setupState, data, props, and CTX contain the key, and return the value if they do. Note that this order of judgment is important, as it determines the priority of fetching data if the key is the same. For example:

<template>
  <p>{{msg}}</p>
</template>
<script>
  import { ref } from 'vue'
  export default {
    data() {
      return {
        msg: 'msg from data'
      }
    },
    setup() {
      const msg = ref('msg from setup')
      return {
        msg
      }
    }
  }
</script>
Copy the code

We define the MSG variable in both data and setup, but the final output is “MSG from setup” because setupState takes precedence over data.

Back in the get function, we can see that accessCache is defined as the attribute accessCache of the rendering agent. What does it do? Components frequently access data during rendering to trigger get functions, the most expensive part of which is to call hasOwn multiple times to determine if the key is in a certain type of data, but it is much faster to perform simple property access on ordinary objects. AccessCache [key] is used to cache the data for the first time. The next time we search for the data based on the key, we can directly obtain the corresponding value from accessCache[key] without calling hasOwn. This is also a performance optimization tip.

If the key starts with $, then a series of decisions are made to determine whether it is a $XXX property or method (such as $parent) that is exposed internally by Vue, and then whether it is a key that has been injected by vue-loader into the CSS module. Next, determine whether a user-defined key starting with $is a global attribute. If not, two types of warnings will be reported in non-production environments. The first is for data defined in data that starts with $, because $is a reserved character and will not be used as a proxy, and the second is for variables used in the template that are not defined.

When we modify the instance. CTX render context, we enter the set function. Let’s look at the implementation of the set function:

const PublicInstanceProxyHandlers = {
  set ({ _: instance }, key, value) {
    const { data, setupState, ctx } = instance
    if(setupState ! == EMPTY_OBJ && hasOwn(setupState, key)) {// Assign setupState
      setupState[key] = value
    }
    else if(data ! == EMPTY_OBJ && hasOwn(data, key)) {// Assign a value to data
      data[key] = value
    }
    else if (key in instance.props) {
      // Can't assign props directly(process.env.NODE_ENV ! = ='production') &&
      warn(`Attempting to mutate prop "${key}". Props are readonly.`, instance)
      return false
    }
    if (key[0= = ='$' && key.slice(1) in instance) {
      // Cannot assign a value to a reserved attribute starting with $inside Vue(process.env.NODE_ENV ! = ='production') &&
      warn(`Attempting to mutate public property "${key}". ` +
        `Properties starting with $ are reserved and readonly.`, instance)
      return false
    }
    else {
      // User-defined data assignment
      ctx[key] = value
    }
    return true}}Copy the code

This function assigns values to properties in the render context instance. CTX. It actually assigns values to the corresponding data type. And then props.

Let’s modify the previous example by adding a method:

<template>
  <p>{{ msg }}</p>
  <button @click="random">Random msg</button>
</template>
<script>
  import { ref } from 'vue'
  export default {
    data() {
      return {
        msg: 'msg from data'
      }
    },
    setup() {
      const msg = ref('msg from setup')
      return {
        msg
      }
    },
    methods: {
      random() {
        this.msg = Math.random()
      }
    }
  }
</script>
Copy the code

If we click the button, random will be executed. In this case, this refers to instance. CTX. If we modify this. MSG, set will be triggered, so we will change the value of MSG in setupState.

Note that if we were to assign directly to the data in props, we would get a warning in a non-production environment, because modifying the props directly would not be consistent with the idea of one-way data flow. If we were to assign to a reserved property inside the Vue that starts with $, we would also get a warning.

If it is user-defined data, such as data defined within the Created lifecycle, it is only used for component context sharing, as follows:

export default {
  created() {
    this.userMsg = 'msg from user'}}Copy the code

When this. UserMsg is assigned, the set function is triggered and the userMsg is retained in CTX.

The last is the has proxy process. When we determine if the property exists in the instance. CTX rendering context, we call the HAS function, which is rarely used in projects. For example, when we execute the ‘MSG’ in this from the Created hook function, It triggers the has function.

export default {
  created () {
    console.log('msg' in this)}}Copy the code

Let’s look at the implementation of the has function:

const PublicInstanceProxyHandlers = {
  has
    ({ _: { data, setupState, accessCache, ctx, type, appContext } }, key) {
    // Judge in turn
    return(accessCache[key] ! = =undefined|| (data ! == EMPTY_OBJ && hasOwn(data, key)) || (setupState ! == EMPTY_OBJ && hasOwn(setupState, key)) || (type.props && hasOwn(normalizePropsOptions(type.props)[0], key)) ||
      hasOwn(ctx, key) ||
      hasOwn(publicPropertiesMap, key) ||
      hasOwn(appContext.config.globalProperties, key))
  }
}
Copy the code

The implementation of this function is simple. It checks whether the key is present in accessCache, data, setupState, props, user data, public properties, and global properties, and then returns the result.

Now that we know how to create a context proxy, let’s go back to the setupStatefulComponent function and examine the second process, which determines how to handle the setup function.

Decide to handle the setup function

Let’s take a look at the code involved in the entire logic:

// Decide to handle the setup function
const { setup } = Component
if (setup) {
  If the setup function takes parameters, a setupContext is created
  const setupContext = (instance.setupContext =
    setup.length > 1 ? createSetupContext(instance) : null)
  // Execute the setup function to get the result
  const setupResult = callWithErrorHandling(setup, instance, 0 /* SETUP_FUNCTION */, [instance.props, setupContext])
  // Process the setup execution result
  handleSetupResult(instance, setupResult)
}
Copy the code

If we define a setup function in the component, the next step is to process the setup function, which consists of three steps: creating the setup function context, executing the setup function and getting the result, and processing the setup function execution result.

First determine the length of the setup function argument, if greater than 1, create the setupContext context.

const setupContext = (instance.setupContext =
    setup.length > 1 ? createSetupContext(instance) : null)
Copy the code

We know that the first parameter props corresponds to the props data passed in by the parent component, and the second parameter CTX is an object, which is essentially a setupContext.

Let’s look at creating setupContext using createSetupContext:

function createSetupContext (instance) {
  return {
    attrs: instance.attrs,
    slots: instance.slots,
    emit: instance.emit
  }
}
Copy the code

This returns an object containing the attrs, slots, and emit attributes. SetupContext lets you get component properties, slots, and method emit emit from inside the setup function.

Execute the setup function and get the result with this line:

const setupResult = callWithErrorHandling(setup, instance, 0 /* SETUP_FUNCTION */, [instance.props, setupContext])
Copy the code

Let’s look at the implementation of the callWithErrorHandling function:

function callWithErrorHandling (fn, instance, type, args) {
  let res
  try{ res = args ? fn(... args) : fn() }catch (err) {
    handleError(err, instance, type)
  }
  return res
}
Copy the code

So the first argument to setup is instance.props, and the second argument is setupContext. If there is a JavaScript execution error during the function execution, it will catch the error and execute the handleError function to handle it.

After executing the setup function and getting the result returned, the handleSetupResult function is used to process the result.

handleSetupResult(instance, setupResult)
Copy the code

Let’s look at the implementation of the handleSetupResult function in detail:

function handleSetupResult(instance, setupResult) {
  if (isFunction(setupResult)) {
    // setup returns the render function
    instance.render = setupResult
  }
  else if (isObject(setupResult)) {
    // Make the setup result responsive
    instance.setupState = reactive(setupResult)
  }
  finishComponentSetup(instance)
}
Copy the code

As you can see, when setupResult is an object, we make it reactive and assign it to instance.setupState, so that when the template is rendered, according to the previous proxy rules, Instance. CTX gets the corresponding data from instance.setupState, which establishes a connection between the setup function and the template rendering. In addition, Setup supports not only returning an object, but also returning a function as a rendering function of a component.

At the end of the handleSetupResult, the finishComponentSetup function is executed to setup the component instance. Personally, it makes more sense to extract it outside and execute it after the handleSetupResult function. In addition, the finishComponentSetup function is used to set the component instance when the component does not have a setup defined.

The component instance is set up

Let’s look at the implementation of the finishComponentSetup function:

function finishComponentSetup (instance) {
  const Component = instance.type
  // Normalize the template or render function
  if(! instance.render) {if(compile && Component.template && ! Component.render) {// Compile at runtime
      Component.render = compile(Component.template, {
        isCustomElement: instance.appContext.config.isCustomElement || NO
      })
      Component.render._rc = true
    }
    if((process.env.NODE_ENV ! = ='production') && !Component.render) {
      if(! compile && Component.template) {// Only the run-time version of template was written
        warn(`Component provided template option but ` +
          `runtime compilation is not supported in this build of Vue.` +
          (` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".`
          ) /* should not happen */)}else {
        // No render function, no template
        warn(`Component is missing template or render function.`)}}// The component object's render function is assigned to instance
    instance.render = (Component.render || NOOP)
    if (instance.render._rc) {
      // For run-time compiled rendering functions that use the with block, use a proxy for the new rendering context
      instance.withProxy = new Proxy(instance.ctx, RuntimeCompiledPublicInstanceProxyHandlers)
    }
  }
  // Compatible with Vue2 options-API
  {
    currentInstance = instance
    applyOptions(instance, Component)
    currentInstance = null}}Copy the code

Functions do two main things: standardize templates or render functions and compatibility with options-API. Let’s look at these two processes in detail.

Standardized templates or rendering functions

Before we analyze this process, we need to know some background. The component eventually generates a subtree vNode by running the Render function, but we rarely write the Render function directly and usually develop components in one of two ways.

  1. The first is to develop Components using Single File Components (SFC), which describes the DOM structure of a component by writing a component template template. We know that.vue files cannot be loaded directly on the Web side, so during the compilation phase of Webpack, it will compile and generate component-related JavaScript and CSS through vue-loader. Add the template part to the render function to the properties of the component object.

  2. Another development approach is to introduce Vue directly without webpack compilation. Out of the box, we write the component template directly in the component object template property, and then compile the Render function at run time. This approach is usually used for older projects with some historical baggage.

Therefore, there are two versions of Vue on the Web side: Runtime-only and Runtime-compiled. We prefer the Runtime-only version of Vue because it is relatively small, does not compile at runtime, takes less time, and performs better. In cases where there is no alternative, such as the old project mentioned above, we can also choose Runtime Compiled.

The main difference between runtime-only and Run-time compiled is whether the compile method is registered.

In Vue3, the compile method is externally registered:

let compile;
function registerRuntimeCompiler(_compile) {
    compile = _compile;
}
Copy the code

Going back to the normalized template or render function logic, let’s first see if instance.render exists, and if not, start the normalization process. Here are three main cases to deal with.

  1. The compile and component template attributes exist and the Render method does not. At this point, run-time compiled version generates the Render function by compiling the template while JavaScript is running.

  2. The compile and Render methods do not exist and the component template property does. As compile is not available, run-time only version is used, so a warning should be generated to tell the user that the run-time version of Vue is used if you want it compiled at runtime.

  3. The component does not write either the Render function or the template template, and sends a warning to the user that the component is missing either the Render function or the template template.

After that, we assign the component’s render function to instance.render, and when it’s time for the component to render, we run the instance.render function to generate the component’s subtree vNodes.

For use with other pieces of runtime compilation of rendering function, rendering context agent is RuntimeCompiledPublicInstanceProxyHandlers, It is in before rendering context agent PublicInstanceProxyHandlers extension, on the basis of the main to realize optimized from the function:

constRuntimeCompiledPublicInstanceProxyHandlers = { ... PublicInstanceProxyHandlers,get(target, key) {
    if (key === Symbol.unscopables) {
      return
    }
    return PublicInstanceProxyHandlers.get(target, key, target)
  },
  has(_, key) {
    // Has is false if key begins with an _ or is in the global whitelist
    const has = key[0]! = ='_' && !isGloballyWhitelisted(key)
    if((process.env.NODE_ENV ! = ='production') && !has && PublicInstanceProxyHandlers.has(_, key)) {
      warn(`Property The ${JSON.stringify(key)} should not start with _ which is a reserved prefix for Vue internals.`)}return has
  }
}
Copy the code

If key begins with an _, or if key is in the global whitelist, then has is false.

Now that we’ve seen the flow of standardized templates or rendering functions, let’s look at the final process for setting up a component instance — the VUe2-compliant Options-API.

Compatible with Vue2 options-API

We know that Vue2 describes a component as a component object, and Vue3 still supports the Vue2 options-API, which is implemented through the applyOptions method.

function applyOptions(instance, options, deferredData = [], deferredWatch = [], asMixin = false) {
  const {
    / /
    mixins, extends: extendsOptions,
    // Array state
    props: propsOptions, data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions,
    // Components and directives
    components, directives,
    // Lifecycle
    beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeUnmount, unmounted, renderTracked, renderTriggered, errorCaptured } = options;

  // instance.proxy 作为 this
  const publicThis = instance.proxy;
  const ctx = instance.ctx;

  // Handle global mixins
  / / handle the extend
  // Handle local mixins
  // props is already handled outside
  Inject / / processing
  // The processing method
  / / the data processing
  // Process computed properties
  / / processing watch
  Dojo.provide / / processing
  // Process components
  // Process instructions
  // Handle life cycle options
}
Copy the code

The code for applyOptions is very long, so only the comments list what it does. If you know how Vue2 works, you can easily understand this code.

conclusion

We mainly analyze the component initialization process, including creating component instances and setting up component instances. In further detail, we also learned about the proxy process for rendering contexts, the timing of setup initiation functions in comaction-API, how to establish a connection between setup returns and template rendering, and the standardization process for component-defined templates or rendering functions. See how Vue2’s options-API is compatible.

Finally, let’s take a look at the Vue3 component initialization process:



Due to limited space, only the simplified code is posted in this article. The repository address of the source code involved in this article is as follows:

packages/runtime-core/src/renderer.ts

packages/runtime-core/src/component.ts

packages/runtime-core/src/errorHandling.ts

If you have a better understanding of the setup function after reading this article, please give me a thumbs up at 😄! If there is something wrong, I hope we can correct it and make progress together